home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xpaint-2.1.1
/
help.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
13KB
|
575 lines
/* +-------------------------------------------------------------------+ */
/* | Copyright 1993, David Koblas (koblas@netcom.com) | */
/* | | */
/* | Permission to use, copy, modify, and to distribute this software | */
/* | and its documentation for any purpose is hereby granted without | */
/* | fee, provided that the above copyright notice appear in all | */
/* | copies and that both that copyright notice and this permission | */
/* | notice appear in supporting documentation. There is no | */
/* | representations about the suitability of this software for | */
/* | any purpose. this software is provided "as is" without express | */
/* | or implied warranty. | */
/* | | */
/* +-------------------------------------------------------------------+ */
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Toggle.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Text.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include <ctype.h>
#include "misc.h"
#define TAB_DISTANCE 4
static String helpText[] = {
#include "Help.txt.h"
};
typedef struct HelpInfo_s {
char *name, *topic;
int index;
int start, stop;
struct HelpInfo_s *next;
} HelpInfo;
typedef struct {
Widget shell;
int curTopic;
Widget topicList, topicPort;
Widget textText, textTitle;
Widget nextButton, prevButton;
Widget scrollbar;
int ninfo;
String *topics;
HelpInfo *info;
} LocalInfo;
static Widget toplevel;
/*
** Build heirarchitcal help information structures.
*/
char *matchGet(char *line, char *pat)
{
static char buf[256];
int len = strlen(pat);
char *sp, *ep;
if (strncmp(line, pat, len) != 0)
return NULL;
for (sp = line + len; isspace(*sp); sp++);
for (ep = sp; isalnum(*ep); ep++);
strncpy(buf, sp, ep - sp);
buf[ep-sp] = '\0';
return buf;
}
static HelpInfo *buildInfo(int *count)
{
Boolean nc, flg;
int depth = 0, stop = -1;
int i, j;
char parts[10][20];
HelpInfo *head = NULL, **nxt = &head, *cur = NULL;
char *cp, *tp = NULL;
int idx = 0;
if (count != NULL)
*count = 0;
for (i = 0; i < XtNumber(helpText); i++) {
flg = nc = False;
if ((cp = matchGet(helpText[i], "#BEGIN")) != NULL) {
int argc;
char *argv[128];
char buf[256];
nc = True;
strcpy(buf, helpText[i]); /* Need R&W buffer */
StrToArgv(buf, &argc, argv);
strcpy(parts[depth], argv[1]);
tp = (argc > 2) ? argv[2] : argv[1];
} else if ((cp = matchGet(helpText[i], "#PUSH")) != NULL) {
depth++;
flg = True;
} else if ((cp = matchGet(helpText[i], "#POP")) != NULL) {
if (depth > 0)
depth--;
flg = True;
} else if ((cp = matchGet(helpText[i], "#NL")) != NULL) {
stop = i;
} else {
stop = i;
}
if (nc) {
int len;
if (cur != NULL) {
cur->stop = stop + 1;
*nxt = cur;
nxt = &cur->next;
}
cur = XtNew(HelpInfo);
cur->index = idx++;
cur->start = i + 1;
cur->next = NULL;
if (count != NULL)
(*count)++;
len = 0;
for (j = 0; j <= depth; j++)
len += strlen(parts[j]) + 1;
cur->name = (char*)XtMalloc(len + 1);
cur->name[0] = '\0';
for (j = 0; j <= depth; j++) {
strcat(cur->name, parts[j]);
strcat(cur->name, ".");
}
cur->name[strlen(cur->name)-1] = '\0';
cur->topic = (char*)XtMalloc(strlen(tp) + 7 + 2 * depth);
for (j = 0; j < depth * 2; j++)
cur->topic[j] = ' ';
cur->topic[j] = '\0';
strcat(cur->topic, tp);
strcat(cur->topic, " ");
} else if (flg) {
if (cur->start == i)
cur->start++;
}
}
if (cur != NULL) {
cur->stop = i;
*nxt = cur;
nxt = &cur->next;
}
return head;
}
static void doneCB(Widget w, XtPointer lArg, XtPointer junk)
{
LocalInfo *l = (LocalInfo*)lArg;
XtPopdown(l->shell);
}
static char *buildText(HelpInfo *cur)
{
int i, len;
char *txt;
char *tp, *cp;
len = 0;
for (i = cur->start; i < cur->stop; i++)
len += strlen(helpText[i]) + 2;
tp = txt = (char*)XtCalloc(len + 8, sizeof(char));
for (i = cur->start; i < cur->stop; i++) {
/*
** Line of all whitespace is a paragraph break.
*/
for (cp = helpText[i]; *cp != '\0'; cp++)
if (!isspace(*cp))
break;
if (*cp == '\0') {
*tp++ = '\n';
*tp++ = '\n';
continue;
}
if (strncmp(helpText[i], "#NL", 3) == 0) {
*tp++ = '\n';
continue;
}
for (cp = helpText[i]; *cp != '\0'; *tp++ = *cp++);
*tp++ = ' ';
}
*tp++ = '\n';
*tp = '\0';
return txt;
}
static void display(LocalInfo *l, HelpInfo *cur)
{
char *txt;
float self, top, shown;
if (cur == NULL)
cur = l->info;
l->curTopic = cur->index;
txt = buildText(cur);
XtVaSetValues(l->textText, XtNstring, txt, NULL);
XtVaSetValues(l->textTitle, XtNlabel, cur->topic, NULL);
XtFree((XtPointer)txt);
XtVaSetValues(l->nextButton, XtNsensitive, (cur->next != NULL), NULL);
XtVaSetValues(l->prevButton, XtNsensitive, (cur->index != 0), NULL);
XtCallActionProc(l->textText, "beginning-of-file", NULL, NULL, 0);
/*
** Now position the scrollbar to be visible
*/
XtVaGetValues(l->scrollbar, XtNtopOfThumb, &top,
XtNshown, &shown,
NULL);
self = (float)cur->index / (float)l->ninfo;
if (self < top || self > top + shown) {
static String args[] = { "Forward" };
top = self - shown / 2.0;
if (top < 0.0)
top = 0.0;
if (top + shown > 1.0)
top = 1.0 - shown;
/*
** Scrollbar doesn't notify on a SetThumb()
** So we must do it
*/
XawScrollbarSetThumb(l->scrollbar, top, -1.0);
XtCallCallbacks(l->scrollbar, XtNjumpProc, (XtPointer)&top);
}
}
static void topicCB(Widget w, LocalInfo *l, XawListReturnStruct *list)
{
HelpInfo *cur = l->info;
int i;
for (i = 0; i < list->list_index; i++)
cur = cur->next;
display(l, cur);
}
static void downCB(Widget w, LocalInfo *l, XtPointer junk)
{
XtCallActionProc(l->textText, "next-page", NULL, NULL, 0);
}
static void upCB(Widget w, LocalInfo *l, XtPointer junk)
{
XtCallActionProc(l->textText, "previous-page", NULL, NULL, 0);
}
static void prevCB(Widget w, LocalInfo *l, XtPointer junk)
{
XawListReturnStruct lrs;
if (l->curTopic == 0)
return;
lrs.list_index = l->curTopic - 1;
XawListHighlight(l->topicList, lrs.list_index);
topicCB(w, l, &lrs);
}
static void nextCB(Widget w, LocalInfo *l, XtPointer junk)
{
XawListReturnStruct lrs;
if (l->curTopic == l->ninfo - 1)
return;
lrs.list_index = l->curTopic + 1;
XawListHighlight(l->topicList, lrs.list_index);
topicCB(w, l, &lrs);
}
static LocalInfo *buildPopup(LocalInfo *l, Widget parent)
{
Widget shell, form;
Widget title;
Widget topicList, topicPort;
Widget textTitle, textList;
Widget done, prev, next;
Widget pgDown, pgUp;
if (l == NULL) {
HelpInfo *cur;
int i;
l = XtNew(LocalInfo);
l->info = buildInfo(&l->ninfo);
l->topics = (String *)XtCalloc(l->ninfo + 1, sizeof(String));
for (i = 0, cur = l->info; cur != NULL; cur = cur->next, i++)
l->topics[i] = cur->topic;
l->topics[i] = NULL;
l->shell = None;
}
if (l->shell != None)
return l;
shell = XtVaCreatePopupShell("helpDialog",
topLevelShellWidgetClass, GetShell(parent),
NULL);
form = XtVaCreateManagedWidget("form",
formWidgetClass, shell,
XtNborderWidth, 0,
NULL);
title = XtVaCreateManagedWidget("title",
labelWidgetClass, form,
XtNborderWidth, 0,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
/*
**
*/
topicPort = XtVaCreateManagedWidget("topicPort",
viewportWidgetClass, form,
XtNtop, XtChainTop,
XtNbottom, XtChainBottom,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
XtNfromVert, title,
XtNallowVert, True,
XtNforceBars, True,
NULL);
topicList = XtVaCreateManagedWidget("topic",
listWidgetClass, topicPort,
XtNverticalList, True,
XtNforceColumns, True,
XtNdefaultColumns, 1,
NULL);
/*
**
*/
textTitle = XtVaCreateManagedWidget("textTitle",
labelWidgetClass, form,
XtNborderWidth, 0,
XtNfromHoriz, topicPort,
XtNfromVert, title,
XtNleft, XtChainLeft,
XtNright, XtChainRight,
XtNtop, XtChainTop,
XtNbottom, XtChainTop,
XtNresize, False,
NULL);
textList = XtVaCreateManagedWidget("textText",
asciiTextWidgetClass, form,
XtNwrap, XawtextWrapWord,
XtNtop, XtChainTop,
XtNbottom, XtChainBottom,
XtNleft, XtChainLeft,
XtNright, XtChainRight,
XtNfromVert, textTitle,
XtNfromHoriz, topicPort,
XtNscrollVertical, XawtextScrollAlways,
XtNdisplayCaret, False,
NULL);
{
Widget sink;
int tabs[10];
int i;
for (i = 0; i < XtNumber(tabs); i++)
tabs[i] = i * TAB_DISTANCE;
XtVaGetValues(textList, XtNtextSink, &sink, NULL);
XawTextSinkSetTabs(sink, XtNumber(tabs), tabs);
}
/*
**
*/
done = XtVaCreateManagedWidget("done",
commandWidgetClass, form,
XtNfromVert, textList,
XtNtop, XtChainBottom,
XtNbottom, XtChainBottom,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
next = XtVaCreateManagedWidget("next",
commandWidgetClass, form,
XtNfromVert, textList,
XtNfromHoriz, done,
XtNtop, XtChainBottom,
XtNbottom, XtChainBottom,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
prev = XtVaCreateManagedWidget("prev",
commandWidgetClass, form,
XtNfromVert, textList,
XtNfromHoriz, next,
XtNtop, XtChainBottom,
XtNbottom, XtChainBottom,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
pgDown = XtVaCreateManagedWidget("down",
commandWidgetClass, form,
XtNfromVert, textList,
XtNfromHoriz, topicPort,
XtNtop, XtChainBottom,
XtNbottom, XtChainBottom,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
pgUp = XtVaCreateManagedWidget("up",
commandWidgetClass, form,
XtNfromVert, textList,
XtNfromHoriz, pgDown,
XtNtop, XtChainBottom,
XtNbottom, XtChainBottom,
XtNleft, XtChainLeft,
XtNright, XtChainLeft,
NULL);
l->shell = shell;
l->textText = textList;
l->textTitle = textTitle;
l->topicPort = topicPort;
l->topicList = topicList;
l->nextButton = next;
l->prevButton = prev;
l->scrollbar = XtNameToWidget(topicPort, "vertical");
XawListChange(topicList, l->topics, 0, 0, True);
XtAddCallback(topicList, XtNcallback, (XtCallbackProc)topicCB, (XtPointer)l);
XtAddCallback(pgDown, XtNcallback, (XtCallbackProc)downCB, (XtPointer)l);
XtAddCallback(pgUp, XtNcallback, (XtCallbackProc)upCB, (XtPointer)l);
XtAddCallback(next, XtNcallback, (XtCallbackProc)nextCB, (XtPointer)l);
XtAddCallback(prev, XtNcallback, (XtCallbackProc)prevCB, (XtPointer)l);
XtAddCallback(done, XtNcallback, doneCB, (XtPointer)l);
AddDestroyCallback(shell, (void (*)(Widget, void *, XEvent *))doneCB, (XtPointer)l);
return l;
}
void HelpDialog(Widget parent, String name)
{
static LocalInfo *l = NULL;
int i;
HelpInfo *cur;
l = buildPopup(l, toplevel);
for (i = 0, cur = l->info; cur != NULL; cur = cur->next, i++)
if (strcmp(name, cur->name) == 0)
break;
if (!XtIsRealized(l->shell))
display(l, cur);
XawListHighlight(l->topicList, cur == NULL ? 0 : i);
XtPopup(l->shell, XtGrabNone);
display(l, cur);
XMapRaised(XtDisplay(l->shell), XtWindow(l->shell));
}
void HelpTextOutput(FILE *fd, String name)
{
char *txt;
int col, wlen, i;
char *tp, *cp, *wstart;
HelpInfo *head, *cur;
head = buildInfo(NULL);
for (i = 0, cur = head; cur != NULL; cur = cur->next, i++)
if (strcmp(name, cur->name) == 0)
break;
if (cur == NULL)
return;
txt = buildText(cur);
col = wlen = 0;
for (tp = txt; *tp != '\0'; tp++) {
if (isspace(*tp) || *tp == '\n') {
for (i = 0; i < wlen; i++, wstart++)
putc(*wstart, fd);
col += wlen;
wlen = 0;
if (*tp == '\t') {
do {
putc(' ', fd);
col++;
} while (col % TAB_DISTANCE != 0);
} else if (*tp == '\n') {
putc(*tp, fd);
col = 0;
} else {
putc(*tp, fd);
col++;
}
if (col > 75) {
putc('\n', fd);
col = 0;
}
} else if (wlen != 0) {
if (col != 0 && (wlen + col > 75)) {
putc('\n', fd);
col = 0;
}
wlen++;
} else {
wlen = 1;
wstart = tp;
}
}
for (i = 0; i < wlen; i++, wstart++)
putc(*wstart, fd);
if (col != 0)
putc('\n', fd);
XtFree((XtPointer)txt);
}
static void helpAction(Widget w, XEvent *event, String *prms, Cardinal *nprms)
{
if (*nprms != 1) {
fprintf(stderr,"Help called with wrong number of params\n");
return;
}
HelpDialog(w, prms[0]);
}
void HelpInit(Widget top)
{
static XtActionsRec act = { "PaintHelp", (XtActionProc)helpAction };
XtAppAddActions(XtWidgetToApplicationContext(top), &act, 1);
toplevel = top;
}